package com.zlyx.easy.socket.core;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

import com.zlyx.easy.core.annotations.Desc;
import com.zlyx.easy.core.tool.Ops;
import com.zlyx.easy.socket.core.supports.AbstractMsgHandlerFactory;
import com.zlyx.easy.socket.interfaces.IMsgHandler;

/**
 * 
 * @author 赵光
 * @Description: TCP消息处理器工厂
 * @date 2018年11月14日
 */
@Desc("NIO方式处理TCP消息工厂")
public class NioTcpMsgHandlerFactory extends AbstractMsgHandlerFactory {

	ServerSocketChannel serverSocketChannel;
	SocketChannel socketChannel;
	Selector selector;
	byte[] sendText = null;

	public NioTcpMsgHandlerFactory(int port, float size, IMsgHandler<?> handler) throws Exception {
		super(port, size, handler);
		this.serverSocketChannel = ServerSocketChannel.open();
		this.serverSocketChannel.configureBlocking(false);
		this.serverSocketChannel.bind(new InetSocketAddress(this.PORT));
		this.selector = Selector.open();
		this.serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
	}

	@Override
	public boolean doBlock() throws Exception {
		int readyChannels = this.selector.select();
		if (readyChannels > 0) {
			Set<SelectionKey> selectionKeys = this.selector.selectedKeys();
			Iterator<SelectionKey> iterator = selectionKeys.iterator();
			while (iterator.hasNext()) {
				SelectionKey selectionKey = iterator.next();
				handleKey(selectionKey);
				iterator.remove();
			}
		}
		return true;
	}

	private void handleKey(SelectionKey selectionKey) throws Exception {
		ByteBuffer buffer = ByteBuffer.allocate(this.BLOCK);
		if (selectionKey.isAcceptable()) {
			this.serverSocketChannel = ((ServerSocketChannel) selectionKey.channel());
			this.socketChannel = this.serverSocketChannel.accept();
			this.socketChannel.configureBlocking(false);
			this.socketChannel.register(selector, SelectionKey.OP_READ);
		}
		if (selectionKey.isReadable()) {
			this.socketChannel = ((SocketChannel) selectionKey.channel());
			buffer.clear();
			int count = this.socketChannel.read(buffer);
			if (count > 0) {
				String receiveText = new String(buffer.array(), 0, count).trim();
				InetAddress address = socketChannel.socket().getInetAddress();
				this.sendText = doHandler(address, receiveText);
				this.socketChannel.register(selector, SelectionKey.OP_WRITE);
			}
		}
		if (selectionKey.isWritable()) {
			this.socketChannel = ((SocketChannel) selectionKey.channel());
			if (Ops.isNotNull(this.sendText)) {
				this.socketChannel.write(ByteBuffer.wrap(this.sendText));
			}
			this.socketChannel.register(selector, SelectionKey.OP_READ);
		}
	}

	@Override
	public void closeServer() throws Exception {
		if (this.serverSocketChannel != null) {
			this.serverSocketChannel.close();
		}
		if (this.socketChannel != null) {
			this.socketChannel.close();
		}
	}
}
